﻿Imports Microsoft.SharePoint
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.SharePoint.WebControls
Imports System.Security.Permissions
Imports System.Web.UI.HtmlControls

Public Class BengenRecurrenceField
    Inherits SPFieldText

    Public Sub New(ByVal fields As SPFieldCollection, ByVal fieldName As String)
        MyBase.New(fields, fieldName)
    End Sub

    Public Sub New(ByVal fields As SPFieldCollection, ByVal typeName As String, ByVal displayName As String)
        MyBase.New(fields, typeName, displayName)
    End Sub

    Public Overrides Property DefaultValue As String
        Get
            Return BengenRecurrenceFunctions.GetDefaultValue.ToString
        End Get
        Set(ByVal value As String)
            MyBase.DefaultValue = value
        End Set
    End Property

    Public Overrides ReadOnly Property FieldRenderingControl As Microsoft.SharePoint.WebControls.BaseFieldControl
        Get
            Dim ctr As New Bengen.SP.Fields.BengenRecurrenceControl
            ctr.FieldName = Me.InternalName
            Return ctr
        End Get
    End Property

    Public Overrides Function GetValidatedString(ByVal value As Object) As String
        Dim mcv As New SPFieldMultiColumnValue(BengenRecurrenceFunctions.GetFormattedValue(value.ToString))
        Select Case mcv(0)
            Case "Hourly"
                If CInt(mcv(2)) > CInt(mcv(3)) Then
                    Throw New SPFieldValidationException("The start hour must be less than or equal to the end hour.")
                End If

        End Select

        Return BengenRecurrenceFunctions.GetFormattedValue(value.ToString)

    End Function


End Class

Public Class BengenRecurrenceControl
    Inherits BaseFieldControl

#Region " declarations "
    Protected rbHourly As RadioButton
    Protected rbDaily As RadioButton
    Protected rbWeekly As RadioButton
    Protected rbMonthly As RadioButton
    Protected RbMonthlyByDay As RadioButton
    Protected RbMonthlyByDate As RadioButton

    Protected DdlHourlyMinuteBegin As DropDownList
    Protected DdlHourlyStart As DropDownList
    Protected DdlHourlyEnd As DropDownList

    Protected DdlDailyHourBegin As DropDownList
    Protected DdlDailyMinuteBegin As DropDownList

    Protected DdlWeeklyDayBegin As DropDownList
    Protected DdlWeeklyHourBegin As DropDownList
    Protected DdlWeeklyMinuteBegin As DropDownList

    Protected DdlMonthlyByDayHourBegin As DropDownList
    Protected DdlMonthlyByDayMinuteBegin As DropDownList
    Protected DdlMonthlyWeekBegin As DropDownList
    Protected DdlMonthlyDayBegin As DropDownList

    Protected DdlMonthlyByDateHourBegin As DropDownList
    Protected DdlMonthlyByDateMinuteBegin As DropDownList
    Protected DdlMonthlyDateBegin As DropDownList

    Protected DtLastOccurrence As DateTimeControl
    Protected TxtLastOccurrence As InputFormTextBox
    Protected LblNextOccurrence As Label
    Protected DtNextOccurrence As DateTimeControl

    Protected LblSummary As Label

#End Region

    Protected Overrides ReadOnly Property DefaultTemplateName As String
        Get
            If Me.ControlMode = SPControlMode.Display Then
                Return Me.DisplayTemplateName
            Else
                Return "BengenRecurrenceFieldRenderingTemplate"
            End If
        End Get
    End Property

    Public Overrides Property DisplayTemplateName As String
        Get
            Return "BengenRecurrenceFieldRenderingTemplateForDisplay"
        End Get
        Set(ByVal value As String)
            MyBase.DisplayTemplateName = value
        End Set
    End Property

    Protected Overrides Sub CreateChildControls()
        MyBase.CreateChildControls()
        rbHourly = CType(Me.TemplateContainer.FindControl("rbHourly"), RadioButton)
        rbDaily = CType(Me.TemplateContainer.FindControl("rbDaily"), RadioButton)
        rbWeekly = CType(Me.TemplateContainer.FindControl("rbWeekly"), RadioButton)
        rbMonthly = CType(Me.TemplateContainer.FindControl("rbMonthly"), RadioButton)
        RbMonthlyByDay = CType(Me.TemplateContainer.FindControl("RbMonthlyByDay"), RadioButton)
        RbMonthlyByDate = CType(Me.TemplateContainer.FindControl("RbMonthlyByDate"), RadioButton)

        DdlHourlyMinuteBegin = CType(Me.TemplateContainer.FindControl("DdlHourlyMinuteBegin"), DropDownList)
        DdlHourlyStart = CType(Me.TemplateContainer.FindControl("DdlHourlyStart"), DropDownList)
        DdlHourlyEnd = CType(Me.TemplateContainer.FindControl("DdlHourlyEnd"), DropDownList)

        DdlDailyHourBegin = CType(Me.TemplateContainer.FindControl("DdlDailyHourBegin"), DropDownList)
        DdlDailyMinuteBegin = CType(Me.TemplateContainer.FindControl("DdlDailyMinuteBegin"), DropDownList)

        DdlWeeklyDayBegin = CType(Me.TemplateContainer.FindControl("DdlWeeklyDayBegin"), DropDownList)
        DdlWeeklyHourBegin = CType(Me.TemplateContainer.FindControl("DdlWeeklyHourBegin"), DropDownList)
        DdlWeeklyMinuteBegin = CType(Me.TemplateContainer.FindControl("DdlWeeklyMinuteBegin"), DropDownList)

        DdlMonthlyByDayHourBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyByDayHourBegin"), DropDownList)
        DdlMonthlyByDayMinuteBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyByDayMinuteBegin"), DropDownList)
        DdlMonthlyWeekBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyWeekBegin"), DropDownList)
        DdlMonthlyDayBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyDayBegin"), DropDownList)

        DdlMonthlyByDateHourBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyByDateHourBegin"), DropDownList)
        DdlMonthlyByDateMinuteBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyByDateMinuteBegin"), DropDownList)
        DdlMonthlyDateBegin = CType(Me.TemplateContainer.FindControl("DdlMonthlyDateBegin"), DropDownList)

        DtLastOccurrence = CType(Me.TemplateContainer.FindControl("DtLastOccurrence"), DateTimeControl)
        TxtLastOccurrence = CType(Me.TemplateContainer.FindControl("TxtLastOccurrence"), InputFormTextBox)
        LblNextOccurrence = CType(Me.TemplateContainer.FindControl("LblNextOccurrence"), Label)
        DtNextOccurrence = CType(Me.TemplateContainer.FindControl("DtNextOccurrence"), DateTimeControl)

        LblSummary = CType(Me.TemplateContainer.FindControl("LblSummary"), Label)

        If Me.ItemFieldValue Is Nothing Then
            Me.ItemFieldValue = BengenRecurrenceFunctions.GetDefaultValue
        End If

        If Me.ControlMode <> SPControlMode.Display Then
            If Not Me.Page.IsPostBack Then
                If Me.ControlMode = SPControlMode.New Then
                    Dim mcv As New SPFieldMultiColumnValue(Me.ItemFieldValue.ToString)
                    Try
                        Me.SetTemplateValues(mcv)
                    Catch ex As Exception
                    End Try
                End If
            End If
        Else
            If Me.LblSummary IsNot Nothing Then
                Dim mcv As New SPFieldMultiColumnValue(Me.ItemFieldValue.ToString)
                LblSummary.Text = mcv(7)
            End If
        End If
    End Sub

    Public Overrides Property Value As Object
        Get
            Me.EnsureChildControls()
            Dim mcv As SPFieldMultiColumnValue = Me.GetTemplateValues

            Return mcv.ToString.TrimEnd(CChar("#")).TrimEnd(CChar(";"))
        End Get
        Set(ByVal value As Object)
            Me.EnsureChildControls()
            Dim mcv As New SPFieldMultiColumnValue(value.ToString)
            If mcv.Count <> 11 Then
                mcv = New SPFieldMultiColumnValue(BengenRecurrenceFunctions.GetDefaultValue)
            End If
            Try
                Me.SetTemplateValues(mcv)
            Catch ex As Exception
            End Try
        End Set
    End Property

    Private Sub SetTemplateValues(ByVal mcv As SPFieldMultiColumnValue)
        Select Case mcv(0)
            Case "Hourly"
                rbHourly.Checked = True
                DdlHourlyMinuteBegin.SelectedIndex = CInt(mcv(1))
                DdlHourlyStart.SelectedIndex = CInt(mcv(2))
                DdlHourlyEnd.SelectedIndex = CInt(mcv(3))
                ScriptManager.RegisterStartupScript(Me, Me.GetType, "init", "document.getElementById('pnlHourly').className = 'ms-schedpickList show' ;", True)

            Case "Daily"
                rbDaily.Checked = True
                DdlDailyHourBegin.SelectedIndex = CInt(mcv(1))
                DdlDailyMinuteBegin.SelectedIndex = CInt(mcv(2))
                ScriptManager.RegisterStartupScript(Me, Me.GetType, "init", "document.getElementById('pnlDaily').className = 'ms-schedpickList show' ;", True)

            Case "Weekly"
                rbWeekly.Checked = True
                DdlWeeklyDayBegin.SelectedIndex = CInt(mcv(1))
                DdlWeeklyHourBegin.SelectedIndex = CInt(mcv(2))
                DdlWeeklyMinuteBegin.SelectedIndex = CInt(mcv(3))
                ScriptManager.RegisterStartupScript(Me, Me.GetType, "init", "document.getElementById('pnlWeekly').className = 'ms-schedpickList show' ;", True)

            Case "Monthly"
                rbMonthly.Checked = True
                If mcv(1) = "ByDay" Then
                    RbMonthlyByDay.Checked = True
                    DdlMonthlyByDayHourBegin.SelectedIndex = CInt(mcv(2))
                    DdlMonthlyByDayMinuteBegin.SelectedIndex = CInt(mcv(3))
                    DdlMonthlyWeekBegin.SelectedIndex = CInt(mcv(4))
                    DdlMonthlyDayBegin.SelectedIndex = CInt(mcv(5))

                ElseIf mcv(1) = "ByDate" Then
                    RbMonthlyByDate.Checked = True
                    DdlMonthlyByDateHourBegin.SelectedIndex = CInt(mcv(2))
                    DdlMonthlyByDateMinuteBegin.SelectedIndex = CInt(mcv(3))
                    DdlMonthlyDateBegin.SelectedIndex = CInt(mcv(4))
                End If
                ScriptManager.RegisterStartupScript(Me, Me.GetType, "init", "document.getElementById('pnlMonthly').className = 'ms-schedpickList show' ;", True)

        End Select
        If String.IsNullOrEmpty(mcv(8)) Then
            mcv(8) = DateTime.Now.ToString
            mcv(9) = BengenRecurrenceFunctions.GetNextOccurance(mcv)
        End If
        DtLastOccurrence.SelectedDate = DateTime.Parse(mcv(8))
        DtNextOccurrence.SelectedDate = DateTime.Parse(mcv(9))
    End Sub

    Private Function GetTemplateValues() As SPFieldMultiColumnValue
        Dim mcv As New SPFieldMultiColumnValue(11)

        If rbHourly.Checked Then
            mcv(0) = "Hourly"
            mcv(1) = DdlHourlyMinuteBegin.SelectedIndex.ToString
            mcv(2) = DdlHourlyStart.SelectedIndex.ToString
            mcv(3) = DdlHourlyEnd.SelectedIndex.ToString
            mcv(4) = ""
            mcv(5) = ""
            mcv(6) = ""
            mcv(7) = "Hourly, on each " + DdlHourlyMinuteBegin.SelectedItem.Text + ", between " + DdlHourlyStart.SelectedItem.Text + " and " + DdlHourlyEnd.SelectedItem.Text + "."

        ElseIf rbDaily.Checked Then
            mcv(0) = "Daily"
            mcv(1) = DdlDailyHourBegin.SelectedIndex.ToString
            mcv(2) = DdlDailyMinuteBegin.SelectedIndex.ToString
            mcv(3) = ""
            mcv(4) = ""
            mcv(5) = ""
            mcv(6) = ""
            mcv(7) = "Daily, at " + DdlDailyHourBegin.SelectedItem.Text.Substring(0, 2).Trim + ":" + DdlDailyMinuteBegin.SelectedItem.Text + " " + DdlDailyHourBegin.SelectedItem.Text.Substring(DdlDailyHourBegin.SelectedItem.Text.Length - 2, 2)

        ElseIf rbWeekly.Checked Then
            mcv(0) = "Weekly"
            mcv(1) = DdlWeeklyDayBegin.SelectedIndex.ToString
            mcv(2) = DdlWeeklyHourBegin.SelectedIndex.ToString
            mcv(3) = DdlWeeklyMinuteBegin.SelectedIndex.ToString
            mcv(4) = ""
            mcv(5) = ""
            mcv(6) = ""
            mcv(7) = "Weekly, on " + DdlWeeklyDayBegin.SelectedItem.Text + " at " + DdlWeeklyHourBegin.SelectedItem.Text.Substring(0, 2).Trim + ":" + DdlWeeklyMinuteBegin.SelectedItem.Text + " " + DdlWeeklyHourBegin.SelectedItem.Text.Substring(DdlWeeklyHourBegin.SelectedItem.Text.Length - 2, 2)

        ElseIf rbMonthly.Checked Then
            mcv(0) = "Monthly"

            If RbMonthlyByDay.Checked Then
                mcv(1) = "ByDay"
                mcv(2) = DdlMonthlyByDayHourBegin.SelectedIndex.ToString
                mcv(3) = DdlMonthlyByDayMinuteBegin.SelectedIndex.ToString
                mcv(4) = DdlMonthlyWeekBegin.SelectedIndex.ToString
                mcv(5) = DdlMonthlyDayBegin.SelectedIndex.ToString
                mcv(6) = ""
                mcv(7) = "Monthly, at " + DdlMonthlyByDayHourBegin.SelectedItem.Text.Substring(0, 2).Trim + ":" + DdlMonthlyByDayMinuteBegin.SelectedItem.Text + " " + DdlMonthlyByDayHourBegin.SelectedItem.Text.Substring(DdlMonthlyByDayHourBegin.SelectedItem.Text.Length - 2, 2)
                mcv(7) += " on the " + DdlMonthlyWeekBegin.SelectedItem.Text + " " + DdlMonthlyDayBegin.SelectedItem.Text

            ElseIf RbMonthlyByDate.Checked Then
                mcv(1) = "ByDate"
                mcv(2) = DdlMonthlyByDateHourBegin.SelectedIndex.ToString
                mcv(3) = DdlMonthlyByDateMinuteBegin.SelectedIndex.ToString
                mcv(4) = DdlMonthlyDateBegin.SelectedIndex.ToString
                mcv(5) = ""
                mcv(6) = ""
                mcv(7) = "Monthly, at " + DdlMonthlyByDateHourBegin.SelectedItem.Text.Substring(0, 2).Trim + ":" + DdlMonthlyByDateMinuteBegin.SelectedItem.Text + " " + DdlMonthlyByDateHourBegin.SelectedItem.Text.Substring(DdlMonthlyByDateHourBegin.SelectedItem.Text.Length - 2, 2)
                mcv(7) += " on the " + DdlMonthlyDateBegin.SelectedItem.Text
            End If
        End If


        Try
            mcv(8) = DtLastOccurrence.SelectedDate.ToString("MM/dd/yyyy hh:mm:ss tt")
        Catch ex As Exception
            mcv(8) = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
        End Try

        Try
            mcv(9) = BengenRecurrenceFunctions.GetNextOccurance(mcv)
            mcv(10) = DateTime.Parse(mcv(9)).ToString("yyyyMMddHHmmss")

        Catch ex As Exception
            mcv(9) = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
            mcv(10) = DateTime.Now.ToString("yyyyMMddHHmmss")
        End Try

        Return mcv
    End Function


End Class

Public Class BengenRecurrenceFunctions
    Public Shared Function GetNextOccurance(ByVal mcv As SPFieldMultiColumnValue) As String

        Dim lastOccurrence As DateTime = DateTime.Parse(mcv(8))
        Dim nextOccurrence As DateTime = DateTime.Now

        Select Case mcv(0)
            Case "Hourly"
                nextOccurrence = lastOccurrence.AddHours(1)
                nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy hh:" & CInt(mcv(1)) * 15 & " tt"))

                Dim min As DateTime = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy " & CInt(mcv(2)) & ":mm"))
                Dim max As DateTime = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy " & CInt(mcv(3)) & ":mm"))

                If nextOccurrence < min Then
                    nextOccurrence = min
                ElseIf nextOccurrence > max Then
                    nextOccurrence = min.AddDays(1)
                End If

            Case "Daily"
                nextOccurrence = lastOccurrence.AddDays(1)
                nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy " & CInt(mcv(1)) & ":" & CInt(mcv(2)) * 15))

            Case "Weekly"
                nextOccurrence = lastOccurrence.AddDays(7 - Weekday(lastOccurrence, Microsoft.VisualBasic.FirstDayOfWeek.Sunday))

                For i As Integer = 1 To 7
                    nextOccurrence = nextOccurrence.AddDays(1)
                    If CInt(mcv(1)) = i - 1 Then Exit For
                Next

                nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy " & CInt(mcv(2)) & ":" & CInt(mcv(3)) * 15))

            Case "Monthly"
                nextOccurrence = lastOccurrence.AddMonths(1)

                If mcv(1) = "ByDay" Then
                    nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/1/yyyy hh:mm:00 tt")).AddDays(-1)
                    Dim counter As Integer = 0
                    For i As Integer = 1 To 31
                        nextOccurrence = nextOccurrence.AddDays(1)
                        Dim dow As Integer = CInt(mcv(5))

                        If Weekday(nextOccurrence, Microsoft.VisualBasic.FirstDayOfWeek.Sunday) - 1 = CInt(mcv(5)) Then
                            counter += 1
                            If counter = CInt(mcv(4)) + 1 Then
                                Exit For
                            End If
                        End If
                    Next

                    nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/dd/yyyy " & CInt(mcv(2)) & ":" & CInt(mcv(3)) * 15))

                ElseIf mcv(1) = "ByDate" Then
                    Dim dayNum As Integer = Math.Min(CInt(mcv(4)) + 1, System.DateTime.DaysInMonth(Year(nextOccurrence), Month(nextOccurrence)))

                    nextOccurrence = DateTime.Parse(nextOccurrence.ToString("MM/" & dayNum & "/yyyy " & CInt(mcv(2)) & ":" & CInt(mcv(3)) * 15))

                End If

        End Select

        Return nextOccurrence.ToString("MM/dd/yyyy hh:mm:ss tt")
    End Function
    Public Shared Function GetDefaultValue() As String
        Dim mcv As New SPFieldMultiColumnValue(11)
        mcv(0) = "Hourly"
        mcv(1) = "0"
        mcv(8) = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
        Return mcv.ToString
    End Function
    Public Shared Function GetFormattedValue(ByVal value As String) As String
        Dim mcv As New SPFieldMultiColumnValue(value.ToString)

        If mcv.Count <> 11 Then
            mcv = New SPFieldMultiColumnValue(GetDefaultValue())
        End If

        Try
            mcv(8) = DateTime.Parse(mcv(8)).ToString("MM/dd/yyyy hh:mm:ss tt")
        Catch ex As Exception
            mcv(8) = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
        End Try

        Try
            mcv(9) = BengenRecurrenceFunctions.GetNextOccurance(mcv)
            mcv(10) = DateTime.Parse(mcv(9)).ToString("yyyyMMddHHmmss")

        Catch ex As Exception
            mcv(9) = DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss tt")
            mcv(10) = DateTime.Now.ToString("yyyyMMddHHmmss")
        End Try

        Return mcv.ToString.TrimEnd(CChar("#")).TrimEnd(CChar(";"))
    End Function
End Class